package xyz.scootaloo.kami.cloud.lang

import io.vertx.core.json.JsonObject
import xyz.scootaloo.kami.cloud.model.EntityUserSerializer
import xyz.scootaloo.kami.cloud.model.core.StatusCodeSerializer
import xyz.scootaloo.kami.cloud.model.po.*
import kotlin.reflect.KClass

/**
 * @author flutterdash@qq.com
 * @since 2022/4/12 9:27
 */

val serializerCollects = mapOf<KClass<*>, JsonSerializer<*>>(
    AccountFormSerializer.accept() to AccountFormSerializer,
    AccountFormBlockSerializer.accept() to AccountFormBlockSerializer,
    AccountPlaintextFormBlockSerializer.accept() to AccountPlaintextFormBlockSerializer,
    CacheEntrySerializer.accept() to CacheEntrySerializer,
    CacheUpdateExpirySerializer.accept() to CacheUpdateExpirySerializer,
    ContentDecodeBlockSerializer.accept() to ContentDecodeBlockSerializer,
    DigestEncryptBlockSerializer.accept() to DigestEncryptBlockSerializer,
    EncodeTokenSerializer.accept() to EncodeTokenSerializer,
    EntityUserSerializer.accept() to EntityUserSerializer,
    StatusCodeSerializer.accept() to StatusCodeSerializer,
    ServiceResultSerializer.accept() to ServiceResultSerializer,
    TokenGenBlockSerializer.accept() to TokenGenBlockSerializer,
)

inline fun <reified T : JsonSerializable> deserializer(json: JsonObject): T {
    val handler = findSerializer<T>()
    return handler.deserialize(json)
}

inline fun <reified T : JsonSerializable> serializer(any: T): JsonObject {
    val handler = findSerializer<T>()
    return handler.serialize(any)
}

inline fun <reified T : JsonSerializable> findSerializer(): JsonSerializer<T> {
    @Suppress("UNCHECKED_CAST")
    return (serializerCollects[T::class]
        ?: throw IllegalStateException("没有类型为${T::class.simpleName}的解析器")
            ) as JsonSerializer<T>
}

/**
 * 实现此接口, 代表此类型可以序列化或者反序列化, 同时必须向[serializerCollects]注册[JsonSerializer]的实现
 */
interface JsonSerializable

interface JsonSerializer<T : JsonSerializable> {

    fun accept(): KClass<T>

    fun deserialize(json: JsonObject): T

    fun serialize(any: T): JsonObject {
        return JsonObject.mapFrom(any)
    }

}